package cn.kai.basic.service.impl;

import cn.kai.basic.constants.BaseConstant;
import cn.kai.basic.dto.RegisterDto;
import cn.kai.basic.exception.BusinessException;
import cn.kai.basic.service.IVerifyCodeService;
import cn.kai.basic.util.SendSmsUtf8;
import cn.kai.basic.util.StrUtils;
import cn.kai.basic.util.VerifyCodeUtils;
import cn.kai.user.domain.User;
import cn.kai.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * @Author Kai
 * @Date 2022/6/15 19:35
 * @PackageName:cn.kai.basic.service.impl
 * @ClassName: VerifyCodeServiceImpl
 * @Description: 生成验证码业务层实现类
 * @Version 1.0
 */

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;


    /**
     * 图形验证码
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        if(!StringUtils.hasLength(key)){
            throw new BusinessException("key不能为空！！！");
        }
        //生成4位随机数
        String code = StrUtils.getComplexRandomString(4);
        //保存redis，设置过期时间 key为前端传递的uuid，value为code
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);
        //使用2d把code画成图，把图使用Base64编码成字符串并返回
        return VerifyCodeUtils.VerifyCode(100,38,code);
    }

    /**
     * 短信验证码
     * @param dto
     */
    @Override
    public void smsCode(RegisterDto dto) {
//        1.校验
//        1.1.空校验：前端传过来的数据全部要做空校验，即使前端已经做过校验也需要，为了防止有人恶意调接口
        if (StringUtils.isEmpty(dto.getPhone())
                ||StringUtils.isEmpty(dto.getImageCodeKey())
                ||StringUtils.isEmpty(dto.getImageCodeValue())){
            throw new BusinessException("参数不能为空!");
        }
//        1.2.校验图形验证码
//        1.2.1.从redis中获取对应的图形验证码，如果不存在则说明图形验证码已过期，需要用户重新输入
        Object imageCodeValueTemp = redisTemplate.opsForValue().get(dto.getImageCodeKey());
        if (imageCodeValueTemp == null){
            throw new BusinessException("图形验证码已过期，请重新输入!");
        }else if (!imageCodeValueTemp.toString().equalsIgnoreCase(dto.getImageCodeValue())){
//        1.2.2.如果redis中图形验证码存在则和用户所输入的做比对，错误则提示用户图形验证码输入错误，正确则继续
            throw new BusinessException("图形验证码错误，请重新输入!");
        }
//        1.3.校验手机号是否已注册，查数据库看该手机号是否已经注册，已注册则提示用户手机号已注册请直接登录，未注册则继续
        User userTemp = userMapper.loadByPhone(dto.getPhone());
        if (userTemp != null){
            throw new BusinessException("该手机号已注册，请直接登录！");
        }
//        2.短信验证码
//        2.1.用注册标识符加用户的手机号组成redis的key
        String smsCodeKey = BaseConstant.RegisterConstants.REGISTER_SMS_PREFIX + dto.getPhone();
//        2.2.用该key去redis中查询是否有数据
        Object smsCodeValueTemp = redisTemplate.opsForValue().get(smsCodeKey);

        String smsCode = "";
//        2.2.1.如果数据存在
        if (smsCodeValueTemp != null){
//        2.2.1.1.通过value中的时间戳进行判断时间是否超过一分钟，未超过则报错(虽然前端做了计时器，但是防止它人恶意调用接口),超过一分钟则继续
            Long oldTime = Long.valueOf(smsCodeValueTemp.toString().split(":")[1]);
            if (System.currentTimeMillis() - oldTime < 1*60*1000){
                throw new BusinessException("**************!!!");
            }
//        2.2.1.2.通过value中的时间戳进行判断时间是否超过3分钟，未超过则拿到value中的验证码重新发短信并更新时间戳，超过了则生成新的验证码发送验证短信
            smsCode = smsCodeValueTemp.toString().split(":")[0];
        }else {
//        2.2.2.如果数据不存在则直接生成新的验证码
            smsCode = StrUtils.getRandomString(6);
        }
//        3.存储redis，设置过期时间
        String smsCodeVlaue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(smsCodeKey,smsCodeVlaue,3,TimeUnit.MINUTES);
//        4.发送短信
        SendSmsUtf8.sendSms(dto.getPhone(),smsCode);

    }
}
